import java.applet.Applet;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.image.BufferedImage;
import java.util.LinkedList;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.Timer;

public class OurApplet extends Applet implements ActionListener{

	public static final int TILE_SIZE = 32, FRAME_RATE = 30; //arbitrary
	public int moveDir = 0;
	public static int oldDir = 0;
	public static boolean talking = false;
	Map m;
	Player p;
	Timer timer;
	BufferedImage buffer;
	LinkedList<Integer> keyStack;
	public static Animation grass, darkGrass, water, dirt, flower, darkFlower, tree, darkTree, skinnytree, trimmedtree, wall, brick, blacktile, whitetile, mountaintile, rightcornertile, leftcornertile, skytile, stairtile, walltile, bridge;
	int tempCount = 0;
	private Image offScreenImage;
	private Dimension offScreenSize;
	private Graphics offScreenGraphics;
	public final synchronized void update (Graphics g){
		Dimension d = getSize();
		if((offScreenImage == null) ||(d.width != offScreenSize.width)|| (d.height !=offScreenSize.height))
		{
		offScreenImage = createImage(d.width,d.height);
		offScreenSize = d;
		offScreenGraphics = offScreenImage.getGraphics();
		}
		offScreenGraphics.clearRect(0,0,d.width, d.height);
		paint(offScreenGraphics);
		g.drawImage(offScreenImage,0,0,null);
	}
	

	// This method is mandatory, but can be empty (i.e., have no actual code).
	public void init() { 
		grass = new Animation(new ImageIcon[] {new ImageIcon("Images/GrassTile.png")}, false);
		darkGrass = new Animation(new ImageIcon[] {new ImageIcon("Images/DarkGrassTile.png")}, false);
	    water = new Animation(new ImageIcon[] {new ImageIcon("Images/WaterTile1.png"), new ImageIcon("Images/WaterTile2.png")}, true, 20, "");
		dirt = new Animation(new ImageIcon[] {new ImageIcon("Images/DirtRoadTile.png")}, false);
		flower = new Animation(new ImageIcon[] {new ImageIcon("Images/FlowerTile.png")}, false);
		darkFlower = new Animation(new ImageIcon[] {new ImageIcon("Images/DarkFlowerTile.png")}, false);
		tree = new Animation(new ImageIcon[] {new ImageIcon("Images/Tree.png")}, false);
		darkTree = new Animation(new ImageIcon[] {new ImageIcon("Images/DarkTree.png")}, false);
		skinnytree = new Animation(new ImageIcon[] {new ImageIcon("Images/SkinnyTree.png")}, false);
		trimmedtree = new Animation(new ImageIcon[] {new ImageIcon("Images/TrimmedTree.png")}, false);
		wall = new Animation(new ImageIcon[] {new ImageIcon("Images/BrickWall.png")}, false);
		brick = new Animation(new ImageIcon[] {new ImageIcon("Images/BrickTile.png")}, false);
		blacktile = new Animation(new ImageIcon[] {new ImageIcon("Images/BlackTile.png")}, false);
		whitetile = new Animation(new ImageIcon[] {new ImageIcon("Images/WhiteTile.png")}, false);
		mountaintile = new Animation(new ImageIcon[] {new ImageIcon("Images/RockTile.png")}, false);
		rightcornertile = new Animation(new ImageIcon[] {new ImageIcon("Images/RockTileCornerRight.png")}, false);
		leftcornertile = new Animation(new ImageIcon[] {new ImageIcon("Images/RockTileCornerLeft.png")}, false);
		skytile = new Animation(new ImageIcon[] {new ImageIcon("Images/Sky.png")}, false);
		stairtile = new Animation(new ImageIcon[] {new ImageIcon("Images/StairTile.png")}, false);
		walltile = new Animation(new ImageIcon[] {new ImageIcon("Images/IndoorWall.png")}, false);
		bridge = new Animation(new ImageIcon[] {new ImageIcon("Images/BridgeTile.png")}, false);
		setSize(new Dimension(480, 480));
		p = new Player(20, 20, 10);
		m = new Map("Crossroads.txt", p);
		
		World.getInstance().setMap(m);
		addKeyListener(new MyKeyListener());
		buffer = new BufferedImage(World.getInstance().getMap().getWidth()*TILE_SIZE,World.getInstance().getMap().getHeight()*TILE_SIZE, BufferedImage.TYPE_INT_ARGB);
		timer = new Timer(1000/FRAME_RATE, this);
		timer.start();
		keyStack = new LinkedList<Integer>();
		setFocusable(true);
	}

	// This method is mandatory, but can be empty.(i.e.,have no actual code).
	public void stop() { }

	// Draw everything
	public void paint(Graphics g) {
		if (tempCount < 20){
			g.drawString("You decide to go exploring...(" + (((20-tempCount)/30)+1) +" seconds left...)", 120, 120);
		} else {
		super.paint(g);
		Graphics g2 = buffer.getGraphics();
		g2.setColor(Color.black);
		World.getInstance().draw(g2);
		//g.drawImage(buffer, 0, 0, null);
		g.drawImage(buffer, (7*32)-(World.getInstance().getMap().player.getX()*32+World.getInstance().getMap().player.getXOffset()), (7*TILE_SIZE)-(World.getInstance().getMap().player.getY()*TILE_SIZE+World.getInstance().getMap().player.getYOffset()), World.getInstance().getMap().getWidth()*TILE_SIZE, World.getInstance().getMap().getHeight()*TILE_SIZE, /*World.getInstance().map.getWidth()*32*/ /*World.getInstance().map.getHeight()*32*/ null);
		}
		tempCount++;
	}
	
	@Override
	public void actionPerformed(ActionEvent e) {
		buffer = new BufferedImage(World.getInstance().getMap().getWidth()*TILE_SIZE, World.getInstance().getMap().getHeight()*TILE_SIZE, BufferedImage.TYPE_INT_ARGB);
		if (!keyStack.isEmpty()) moveDir = keyStack.getFirst().intValue();
		else {
			moveDir = 0;
		}
		if (!p.getMoving()) {
			oldDir = moveDir;
		}
		if (moveDir == oldDir){
			World.getInstance().getMap().player.getCurrentAnimation().start();
		}
		if (!p.getMoving() && keyStack.isEmpty()){
			World.getInstance().getMap().player.getCurrentAnimation().stop();
			World.getInstance().getMap().player.getCurrentAnimation().setCurrentFrame(0);
		}
		if (moveDir != 0 || p.getMoving()) World.getInstance().movePlayer(oldDir);
		water.update();
		repaint();
	}

	private class MyKeyListener implements KeyListener {

		Integer one = 1, two = 2, three = 3, four = 4;
		@Override
		public void keyPressed(KeyEvent e) {
			int keyCode = e.getKeyCode();
			switch (keyCode) {
			case KeyEvent.VK_RIGHT :
				if (!keyStack.contains(one) && !talking) keyStack.addFirst(one);
				break;
			case KeyEvent.VK_UP :
				if (!keyStack.contains(two) && !talking) keyStack.addFirst(two);
				break;
			case KeyEvent.VK_LEFT :
				if (!keyStack.contains(three) && !talking) keyStack.addFirst(three);
				break;
			case KeyEvent.VK_DOWN :
				if (!keyStack.contains(four) && !talking) keyStack.addFirst(four);
				break;
			case KeyEvent.VK_SPACE :
				World.getInstance().updateText();
				break;
			case KeyEvent.VK_SHIFT :
				timer.setDelay(1);
				break;
			}
		}

		@Override
		public void keyReleased(KeyEvent e) {
			//System.out.println("Key Released: " + e.getKeyCode());
			int keyCode = e.getKeyCode();
			switch (keyCode) {
			case KeyEvent.VK_RIGHT :
				keyStack.remove(one);
				break;
			case KeyEvent.VK_UP :
				keyStack.remove(two);
				break;
			case KeyEvent.VK_LEFT :
				keyStack.remove(three);
				break;
			case KeyEvent.VK_DOWN :
				keyStack.remove(four);
				break;
			case KeyEvent.VK_SHIFT :
				timer.setDelay(1000/FRAME_RATE);
				break;
			}
		}


		@Override
		public void keyTyped(KeyEvent e) {
		}

	}
	
	public static void main(String[] args){
		JFrame frame = new JFrame("");
		OurApplet m = new OurApplet();
		grass = new Animation(new ImageIcon[] {new ImageIcon("Images/GrassTile.png")}, false);
		darkGrass = new Animation(new ImageIcon[] {new ImageIcon("Images/DarkGrassTile.png")}, false);
	    water = new Animation(new ImageIcon[] {new ImageIcon("Images/WaterTile1.png"), new ImageIcon("Images/WaterTile2.png")}, true, 20, "");
		dirt = new Animation(new ImageIcon[] {new ImageIcon("Images/DirtRoadTile.png")}, false);
		flower = new Animation(new ImageIcon[] {new ImageIcon("Images/FlowerTile.png")}, false);
		darkFlower = new Animation(new ImageIcon[] {new ImageIcon("Images/DarkFlowerTile.png")}, false);
		tree = new Animation(new ImageIcon[] {new ImageIcon("Images/Tree.png")}, false);
		darkTree = new Animation(new ImageIcon[] {new ImageIcon("Images/DarkTree.png")}, false);
		skinnytree = new Animation(new ImageIcon[] {new ImageIcon("Images/SkinnyTree.png")}, false);
		trimmedtree = new Animation(new ImageIcon[] {new ImageIcon("Images/TrimmedTree.png")}, false);
		wall = new Animation(new ImageIcon[] {new ImageIcon("Images/BrickWall.png")}, false);
		brick = new Animation(new ImageIcon[] {new ImageIcon("Images/BrickTile.png")}, false);
		blacktile = new Animation(new ImageIcon[] {new ImageIcon("Images/BlackTile.png")}, false);
		whitetile = new Animation(new ImageIcon[] {new ImageIcon("Images/WhiteTile.png")}, false);
		mountaintile = new Animation(new ImageIcon[] {new ImageIcon("Images/RockTile.png")}, false);
		rightcornertile = new Animation(new ImageIcon[] {new ImageIcon("Images/RockTileCornerRight.png")}, false);
		leftcornertile = new Animation(new ImageIcon[] {new ImageIcon("Images/RockTileCornerLeft.png")}, false);
		skytile = new Animation(new ImageIcon[] {new ImageIcon("Images/Sky.png")}, false);
		stairtile = new Animation(new ImageIcon[] {new ImageIcon("Images/StairTile.png")}, false);
		walltile = new Animation(new ImageIcon[] {new ImageIcon("Images/IndoorWall.png")}, false);
		bridge = new Animation(new ImageIcon[] {new ImageIcon("Images/BridgeTile.png")}, false);
		m.setSize(new Dimension(480, 480));
		m.p = new Player(20, 20, 10);
		m.m = new Map("Crossroads.txt", m.p);
		
		World.getInstance().setMap(m.m);
		m.addKeyListener(m.new MyKeyListener());
		m.buffer = new BufferedImage(World.getInstance().getMap().getWidth()*TILE_SIZE,World.getInstance().getMap().getHeight()*TILE_SIZE, BufferedImage.TYPE_INT_ARGB);
		m.timer = new Timer(1000/FRAME_RATE, m);
		m.timer.start();
		m.keyStack = new LinkedList<Integer>();
		m.setFocusable(true);
		frame.add(m);
		frame.setSize(480, 480);
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.setVisible(true);
	}
}